package com.panda.expand;

/*
    复合语法糖

    该语法糖支持
    形如:
        for:if:div(x in xxx,xxxxx,xxxxx){

        }

    由多个命令混合而成的语法糖


 */

import com.panda.expand.command.*;
import com.panda.pojo.Component;
import com.panda.pojo.Context;
import com.panda.pojo.Element;
import com.google.common.base.Joiner;
import com.panda.utils.Finder;
import com.panda.utils.IdUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CompositeElementSugar extends ElementSugar {

    private Map<String, ParamElementHandler> commandElementHandlerMap;

    {
        //初始化
        commandElementHandlerMap = new HashMap<>();
        addParamElementHandler(If.INSTANCE);
        addParamElementHandler(For.INSTANCE);
        addParamElementHandler(Show.INSTANCE);
        addParamElementHandler(Hide.INSTANCE);
        addParamElementHandler(Click.INSTANCE);
        addParamElementHandler(Include.INSTANCE);

        //碎片
        addParamElementHandler(Fragment.INSTANCE);

    }

    private String regex;

    private Pattern pattern;

    public void addParamElementHandler(ParamElementHandler commandElementHandler) {

        commandElementHandlerMap.put(commandElementHandler.getPrefix() + ":", commandElementHandler);

        Set<String> set = new HashSet<>();

        commandElementHandlerMap.keySet().forEach(s -> {
            set.add("(" + s + ")");
        });

        String p = Joiner.on("|").join(set);

        //重新生成正则
        regex = "(" + p + ")+[a-zA-Z][a-zA-Z0-9]*";

        pattern = Pattern.compile(p);

    }

    @Override
    public boolean canParse(String s, Context context) {
        return s.matches(regex);
    }


    @Override
    public String parseParam(Context context, Element element, String s) {


        if (!(element instanceof CE)) {
            return s;
        }

        if (s == null) {
            s = "";
        }

        Set<String> pst = new HashSet<>();

        Map<String, String> stringMap = context.getStringMap();

        while (s.contains("(")) {

            int start = s.indexOf('(');

            int end = Finder.findParam(s.toCharArray(), start);

            String id = IdUtils.create("__param");

            String p = s.substring(start, end);

            //保护
            s = s.replace(p, id);

            pst.add(id);

            stringMap.put(id, p);

        }

        //分隔后再将参数展开
        String[] ps = s.split(",");

        Set<String> commands = ((CE) element).getCommands();


        int i = 0;

        for (String command : commands) {

            ParamElementHandler handler = commandElementHandlerMap.get(command);

            if (handler.isRepetitive()) {
                element.setRepetitive(true);
            }

            //如果已经没有更多的参数
            if (i >= ps.length) {

                handler.parseParam(context, element, null);

            } else {

                String r = ps[i];

                for (String pt : pst) {
                    r = r.replace(pt, stringMap.get(pt));
                }

                //无法获取字符串

                //如果是字符串就将其展开
                if (r.startsWith("__string_")) {
                    r = context.getStringMap().get(r.trim());
                }

                r = handler.parseParam(context, element, r);

                //如果参数被消费则会跳转到下一个
                if (r == null) {
                    i++;
                }
            }

        }

        if (i == ps.length) {
            return null;
        }

        if (i == ps.length - 1) {
            for (String pt : pst) {

                ps[i] = ps[i].replace(pt, stringMap.get(pt));

            }
            return ps[i];
        }

        throw new RuntimeException("给定的指令参数无法满足需求: " + Joiner.on("").join(commands) + "(" + s + ")");

    }

    @Override
    protected Element makeElement(String e, Context context) {//这里应该考虑两种情形

        Matcher matcher = pattern.matcher(e);

        Set<String> commands = new LinkedHashSet<>();

        //提取命令
        while (matcher.find()) {

            String command = matcher.group();

            commands.add(command);

            e = e.replace(command, "");

        }

        if (targets.contains(e)) {

            CElement cElement = new CElement(context, e);
            cElement.commands = commands;
            return cElement;

        } else if (context.isComponent(e)) {
            CComponent component = new CComponent(context, e);
            component.commands = commands;
            component.setComponentName(e);
            return component;

        }

        throw new RuntimeException("无法识别的标签:" + e);

    }


    private interface CE {

        void setCommands(Set<String> commands);

        Set<String> getCommands();

    }

    private static class CElement extends Element implements CE {

        //有序
        private Set<String> commands;

        CElement(Context context, String name) {
            super(context, name);
        }

        @Override
        public void setCommands(Set<String> commands) {
            this.commands = commands;
        }

        @Override
        public Set<String> getCommands() {
            return commands;
        }
    }


    private static class CComponent extends Component implements CE {

        private Set<String> commands;

        CComponent(Context context, String name) {
            super(context, name);
        }

        public void setCommands(Set<String> commands) {
            this.commands = commands;
        }

        public Set<String> getCommands() {
            return commands;
        }
    }


}


